home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************
- Apple Macintosh Developer Technical Support
-
- Some of "Skippy White's Famous High Level Off-Screen Map Routines"
-
- "off_screen.c"
-
- These routines provide a high-level interface to the QuickDraw & Color
- Manager routines which allow the creation and manipulation of off-screen
- bitmaps and pixmaps. They are designed to run on any machine with 128K or
- later ROMs.
-
- NOTE that I've modified some of Skippy's routines and that, therefore, any
- resultant errors in syntax or logic belong solely to me.
- ****************************************************************************/
-
-
- #include "protos"
-
- #include "globals.h"
- #include "extern.h"
-
-
- // Local Prototype:
- OffScreenRecHdl ErrorOut (OSErr error, OffScreenRecHdl COSHdl);
-
-
- OffScreenRecHdl ErrorOut (OSErr error, OffScreenRecHdl COSHdl) {
-
- (*COSHdl)->CreateOffScreenError = error;
-
- if (error == NewCOSHdlError) return (nil);
- else return (COSHdl);
-
- } /* ErrorOut */
-
-
-
- /* ********** */
- GDHandle GetMaxAreaDevice(Rect *globalRect) {
- /* Find the greatest overlap device for the given global rectangle. */
-
- long area, maxArea;
- GDHandle result, device;
- Rect intersection;
-
-
- result = nil;
- ;
- maxArea = 0;
- ;
- device = GetDeviceList();
-
- while (device != nil) {
- if (TestDeviceAttribute(device, screenDevice)) {
- if (TestDeviceAttribute(device, screenActive)) {
-
- if (SectRect(globalRect, &((**device).gdRect), &intersection)) {
-
- area = (long)(intersection.right - intersection.left) *
- (long)(intersection.bottom - intersection.top);
-
- if (area > maxArea) {
- result = device;
- maxArea = area;
- } /* if area > maxArea */
-
- } /* if SectRect ... */
-
- device = GetNextDevice(device);
- } /* screenActive */
- } /* screenDevice */
- } /* while */
-
- return (result);
-
- } /* GetMaxAreaDevice */
-
-
-
- /**************************
- Just plain nifty stuff ...
- **************************/
-
-
- OffScreenRecHdl CreateOffScreen (Rect *myRect) {
- /* Reference: Tech Note #120
- with special thanks to:
- Jon Zap and
- Forrest Tanaka of MacDTS
-
- NOTE: Local window coordinates are input, but local
- device coordinates are returned for drawing purposes. */
-
- long offRowBytes, sizeOfOff, tempSeed;
- Rect localRect, globRect;
- short maxDepth;
- register short i;
- OSErr err;
- OffScreenRecHdl COSHdl;
-
-
- COSHdl = (OffScreenRecHdl)NewClearHandle(sizeof(OffScreenRec));
-
- if ((err = MemError()) != noErr) return ( ErrorOut(NewCOSHdlError, COSHdl) );
-
- MoveHHi(COSHdl);
- HLock(COSHdl); /* Lock this sucker down !! */
-
- /* CreateOffScreenError = noErr; -- We hope !! */
- GetPort(&( (*COSHdl)->origPort )); /* Used by ToOnScreen. */
- (*COSHdl)->drawingRect = *myRect; /* Saved for use after call to ToOnScreen. */
-
- globRect = *myRect; /* We're about to switch the */
- LocalGlobal(&globRect); /* Port to off-screen: */
-
- if (!gMac2)
- {
- (*COSHdl)->offGrafPtr = &( (*COSHdl)->offGrafPort );
- OpenPort((*COSHdl)->offGrafPtr);
- maxDepth = 1;
- } /* ... a low-life machine */
- else
- {
-
- /* Figure out how much space we need for our pixel image. We call
- mommy ROM's GetMaxDevice to get the pixel map from that.
- We do this to cover the case where the pixel image that we wish to
- CopyBits to spans multiple devices (of possibly different depths). */
-
- (*COSHdl)->myMaxDevice = GetMaxDevice(&globRect);
- if ((*COSHdl)->myMaxDevice == nil) return ( ErrorOut(MaxDevError, COSHdl) );
-
- /* We need to set theGDevice to the device with the maximum pixel
- depth (the one we just found), so the pixel map of the new
- CGrafPort will be copied from one of the proper depth. Save
- the current GDevice for retrieval later and, then, open the
- new CGrafPort to use for our off-screen drawing. */
-
- (*COSHdl)->oldDevice = GetGDevice();
- SetGDevice((*COSHdl)->myMaxDevice);
-
- /* Initialize this guy: */
- (*COSHdl)->offCGrafPtr = &( (*COSHdl)->offCGrafPort );
- OpenCPort((*COSHdl)->offCGrafPtr);
- /* Arrgh !! Batten down the hatches: */
- MoveHHi( ((*COSHdl)->offCGrafPtr)->portPixMap );
- HLock( ((*COSHdl)->offCGrafPtr)->portPixMap );
- maxDepth = (*( ((**COSHdl).offCGrafPtr)->portPixMap ))->pixelSize;
-
- }; /* else: gMac2 */
-
- /* CanNOT use my GlobalLocal PROC because we may have dragged our
- window to a secondary screen. "Global" here is with respect to
- the main screen and "Local" is with respect to the secondary screen.
-
- From Forrest Tanaka:
- When GetMaxDevice returns the secondary screen's GDevice & we set that
- to the current GDevice, then OpenCPort creates a CGrafPort which has a
- portRect = (**((**GetMainDevice).gdPMap)).bounds which is in the global
- coordinates for all the screens' pixel images with a topLeft = (0,0).
- The new (**CGrafPort.portPixMap).bounds is in the local coordinates of
- the secondary screen with a topLeft = (0,-640), for example.
-
- In effect, the port that OpenCPort gives you is NOT a valid port because
- the portRect pertains to the wrong screen. This means that calling
- GlobalLocal shifts the localRect waaaaay over somewhere ... BECAUSE
- the difference between the above portRect and PixMap bounds is SO large: */
-
- localRect = globRect;
- OffsetRect(&localRect, screenBits.bounds.left, screenBits.bounds.top);
-
- /* However, before we do ANYthing more, we should set the
- off-screen's visRgn to the FULL size of the input rect so the
- image stays whole even when the window has been dragged partly
- beyond the physical edge(s) of the screen. Otherwise, the
- (**visRgn).rgnBBox in local coordinates remains equal to
- screenBits.bounds as initialized when _Open(C)Port was called: */
-
- if (gMac2)
- {
- RectRgn( ((*COSHdl)->offCGrafPort).visRgn, &localRect );
- ((*COSHdl)->offCGrafPort).portRect = localRect;
- }
- else
- {
- RectRgn( ((*COSHdl)->offGrafPort).visRgn, &localRect );
- ((*COSHdl)->offGrafPort).portRect = localRect;
- };
-
- /* We are now ready to calculate the size of the pixel image we will need.
- Then we can set the location-specific and size-specific information of
- the pixel map. Since Color QuickDraw distinguishes between a bitmap and
- a pixel map by checking the high bit of rowBytes, we need to set it. */
-
- /* # of words: */
- offRowBytes = (maxDepth * (localRect.right - localRect.left) + 15) / 16;
- if (offRowBytes % 2) offRowBytes++; /* ... made even. */
- offRowBytes *= 2; /* Back to bytes. */
- sizeOfOff = (long)(localRect.bottom - localRect.top) * offRowBytes;
-
- /* Allocate space for the pixel image: */
- (*COSHdl)->myBits = NewClearHandle(sizeOfOff);
- if (MemError() != noErr) return ( ErrorOut(NewBaseAddrPtrError, COSHdl) );
-
- MoveHHi((*COSHdl)->myBits);
- HLock((*COSHdl)->myBits);
-
- /* NOTE that we're filling in the BitMap/PixMap fields of the new Port
- directly, so we do NOT call _SetPortBits or _SetCPortPix later: */
-
- if (gMac2)
- {
- (**( ((**COSHdl).offCGrafPtr)->portPixMap )).baseAddr =
- *( (**COSHdl).myBits );
- /* Remember to be a PixMap: */
- (**( ((**COSHdl).offCGrafPtr)->portPixMap )).rowBytes = offRowBytes | 0x8000;
- (**( ((**COSHdl).offCGrafPtr)->portPixMap )).bounds = localRect;
-
- (**COSHdl).offBitMapPtr =
- (BitMapPtr) (* (((**COSHdl).offCGrafPtr)->portPixMap) );
- } /* if aMac2 */
-
- else /* definitely ... "YUCKY" black-and-white. */
- {
- ((**COSHdl).offGrafPtr)->portBits.baseAddr = *( (**COSHdl).myBits );
- ((**COSHdl).offGrafPtr)->portBits.rowBytes = offRowBytes;
- ((**COSHdl).offGrafPtr)->portBits.bounds = localRect;
-
- (**COSHdl).offBitMapPtr = &( ((**COSHdl).offGrafPtr)->portBits );
- };
-
- if (gMac2)
- {
- /* Next, we clone the color table of the maxDevice
- and put it into our off-screen pixel map. */
-
- (**COSHdl).ourCTHandle = (
- **(( **((*COSHdl)->myMaxDevice) ).gdPMap)
- ).pmTable;
- err = HandToHand(&(**COSHdl).ourCTHandle); /* Clone it. */
- if (err != noErr) return ( ErrorOut(CloneHdlError, COSHdl));
-
- for (i = 0; i <= (**((**COSHdl).ourCTHandle)).ctSize; i++)
- (**((**COSHdl).ourCTHandle)).ctTable[i].value = i;
-
- /* The following is required to convert GDevice cluts to Pixmap cluts: */
-
- (**((**COSHdl).ourCTHandle)).ctFlags &= 0x7FFF;
- tempSeed = GetCTSeed(); /* Thanks, Scott Knaster !! */
- (**((**COSHdl).ourCTHandle)).ctSeed = tempSeed;
- /* --> the off-screen map: */
- (**( ((**COSHdl).offCGrafPtr)->portPixMap )).pmTable = (**COSHdl).ourCTHandle;
- }; /* if gMac2 */
-
- *myRect = localRect; /* Return local screen coordinates. */
-
- return ( ErrorOut(noErr, COSHdl) ); /* Whew !! */
-
- } /* CreateOffScreen*/
-
-
-
- /*******************
- Back to "Square 1":
- *******************/
-
-
- void ToOnScreen (OffScreenRecHdl COSHdl) {
- /* COSHdl is locked coming in. */
-
-
- if (gMac2) SetGDevice((**COSHdl).oldDevice);
- SetPort((**COSHdl).origPort);
-
- } /* ToOnScreen*/
-
-
-
- /****************************
- Out with the new.
-
- Whoops -- I meant the old !!
- **************************** */
-
-
- void DisposOffScreen (OffScreenRecHdl *COSHdl) {
-
-
- if (*COSHdl == nil) return;
-
- if ((***COSHdl).CreateOffScreenError == MaxDevError) goto bye;
-
- /* NewBaseAddrPtrError or CloneHdlError or noErr ... */
-
- if (gMac2)
- {
- if ((***COSHdl).CreateOffScreenError == noErr)
- DisposHandle((***COSHdl).ourCTHandle);
- HUnlock((***COSHdl).offCGrafPtr->portPixMap);
- CloseCPort((***COSHdl).offCGrafPtr);
- }
- else ClosePort((***COSHdl).offGrafPtr);
-
- if ((***COSHdl).CreateOffScreenError != NewBaseAddrPtrError)
- {
- HUnlock((***COSHdl).myBits);
- DisposHandle((***COSHdl).myBits);
- };
-
- bye:
- HUnlock(*COSHdl);
- DisposHandle(*COSHdl);
- *COSHdl = nil; /* Mark as gone ... */
-
- } /* DisposOffScreen */
-
-
-
-
- /* { end file "off_screen.c" } */
-